package client;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * MacheController
 * 
 * handle actions from logingui and MacheGUI. contains all the methods used in
 * the actionListeners. construct ServerResponseWorker to update UI.
 * 
 */
public class MacheController {

    private MacheModel model;
    private LoginGUI logingui;
    private String username;
    private Map<String, MacheGUI> windows;
    private String voiceName = "kevin16";

    /**
     * Constructor for MacheController
     * 
     * @param logingui
     *            the logingui associated with this controller
     * @param test
     *            only used in MacheController Junit test and if testing mode is
     *            on
     * @param m
     *            mock model to be used in testing mode
     */
    public MacheController(LoginGUI logingui, boolean test, MacheModel m) {
        this.logingui = logingui;
        this.model = test ? m : new MacheModel(this);
        this.windows = new HashMap<String, MacheGUI>();
    }

    /**
     * Set the username associated with this MacheController
     * 
     * @param username
     */
    public void setUserID(String username) {
        this.username = username;
    }

    /**
     * Initiate a client to connect to the server Make necessary changes on the
     * model and view
     * 
     * @throws BadUserNameException
     *             if the username is taken
     * @throws IOException
     */
    public void connect(String host, String port) throws BadUserNameException,
            IOException, NumberFormatException {
        model.setUserID(username);
        int portNumber = Integer.parseInt(port);
        MacheClient client = new MacheClient(username, model, host, portNumber,
                false);
        model.setClient(client);
        model.getActiveList();
    }

    /**
     * Signals MacheModel to get the list of all active users currently online.
     */
    public void getActiveList() {
        model.getActiveList();
    }

    /**
     * Get the list of active users for the conversation
     * 
     * @param convID
     */
    public void getActiveListWin(String convID) {
        model.getActiveListWin(convID);
    }

    /**
     * Signal MacheModel to delete the Conversation
     * 
     * @param convID
     */
    public void endConv(String convID) {
        model.endConv(convID);
    }

    /**
     * Signals MacheModel to add invitee to a conversation
     * 
     * @param convID
     * @param invitee
     */
    public void inviteNew(String convID, ArrayList<String> invitees) {
        model.newInvites(convID, invitees);
    }

    /**
     * Signal MacheModel to send a message in the conversation for that user
     * 
     * @param msg
     * @param convID
     */
    public void sendMessage(String font, String message, String convId) {
        Message myMessage = new Message(username, message);
        model.newMessage(font, myMessage, convId);
    }

    /**
     * Signals MacheModel to start a new conversation with a unique ID
     * 
     * @param initialMembers
     */
    public void startConv(ArrayList<String> initialMembers) {
        model.newConv(initialMembers);
    }

    /**
     * Signals model to get the list of users currently in a specific
     * conversation.
     * 
     * @param convID
     */
    public void getUsersInConv(String convID) {
        model.getUsers(convID);
    }

    /**
     * Signals model to inform all users in a specific conversation about the
     * new typing status
     * 
     * @param status
     */
    public void updateStatus(String status, String convID) {
        model.updateStatus(status, convID);
    }

    /**
     * Updates the GUI when a message is received.
     * 
     * @param convID
     * @param message
     */
    public void messageReceived(String convID, String font, Message message) {
        MacheGUI myGUI = windows.get(convID);
        myGUI.addMessage(font, message);
    }
   
    /**
     * Signals model to nudge a friend in a specific conversation.
     * 
     * @param friend
     * @param convID
     */
    public void nudge(String friend, String convID) {
        model.nudge(friend, convID);

    }

    /**
     * Updates the GUI when a conversation is successfully started.
     * 
     * @param convID
     * @param userList
     */
    public void addConv(String convID, List<String> userList) {
        MacheGUI myGUI = new MacheGUI(username,
                (ArrayList<String>) userList, convID, this);
        myGUI.setSize(400, 600);
        myGUI.setVisible(true);
        windows.put(convID, myGUI);
        getActiveListWin(convID);
        getUsersInConv(convID);
    }

    /**
     * Updates the GUI when some users are added to the conversation.
     * 
     * @param convID
     * @param users
     */
    public void usersInConv(String convID, List<String> users) {
        if (windows.containsKey(convID)) {
            MacheGUI myGUI = windows.get(convID);
            myGUI.setNewUsers((ArrayList<String>) users);
        }


    }

    /**
     * Updates the MacheGUI when some user leaves a conversation.
     * 
     * @param convID
     * @param friend
     */
    public void friendLeft(String convID, String friend) {
        MacheGUI myGUI = windows.get(convID);
        myGUI.getUsers().remove(friend);
        myGUI.setUsernameLabel();
        myGUI.renewNudgeTable();
        myGUI.addSystemMessage(friend +" has left the conversation.");
    }

    /**
     * Updates the MacheGUI when some user logs off from the application.
     * 
     * @param friend
     * @param convID
     */
    public void friendLogOff(String friend, String convID) {

        MacheGUI myGUI = windows.get(convID);
        myGUI.getUsers().remove(friend);
        myGUI.setUsernameLabel();
        myGUI.renewNudgeTable();
        myGUI.addSystemMessage(friend+" has logged off.");
    }

    /**
     * Updates the GUI to display the current list of active users online.
     * 
     * @param usersArr
     */
    public void giveActiveList(List<String> usersArr) {
        logingui.emptyActiveList();
        for (String user : usersArr) {
            if (!user.equals(username)) {
                logingui.addActiveUser(user);
            }
        }
    }

    /**
     * Updates the MacheGUI to display the current list of active users
     * online.
     * 
     * @param usersArr
     */
    public void giveActiveListWin(List<String> usersArr, String convID) {
        MacheGUI window = windows.get(convID);
        window.emptyActiveList();
        for (String user : usersArr) {
            window.addActiveUser(user);
        }
    }

    /**
     * Informs the model that the user has exited the application
     */
    public void quit() {
        model.quit();
    }

    /**
     * Close all MacheGUIs that are running
     */
    public void closeAllWindows() {
        Collection<MacheGUI> windowlist = windows.values();
        for (MacheGUI w : windowlist) {
            w.close();
        }
    }

    /**
     * Updates MacheGUI with the new typing status update for a specific
     * user.
     * 
     * @param convID
     * @param username2
     * @param status
     */
    public void typeStatusUpdate(String convID, String username2, String status) {
        MacheGUI window = windows.get(convID);
        window.typeStatusUpdate(username2, status);
    }

    /**
     * Find MacheGUI and make it vibrate.
     * 
     * @param convID
     * @param sender
     */
    public void youGotNudged(String convID, String sender) {
        MacheGUI window = windows.get(convID);
        window.toFront();
        window.repaint();
        window.moveWindow(sender);
    }
    
    /**
     * Informs the user in an old conversation that new users has been invited to the conversation.
     * @param convID
     * @param usersArr
     */
    public void newJoinedFriends(String convID, List<String> usersArr) {
        MacheGUI window = windows.get(convID);
        String message = "";
        if(usersArr.size()>0){
        if (usersArr.size()==1){
            message += usersArr.get(0);
            message+= " has been added to the conversation.";
        }else if(usersArr.size()==2){
            message += usersArr.get(0) +" and " + usersArr.get(1);
            message+= " have been added to the conversation.";  
        }else{
            for (int i=0; i<usersArr.size(); i++){
                if (i!=usersArr.size()-1){
                    message += usersArr.get(i) + ", ";
                }else{
                    message += "and "+usersArr.get(i);
                }
            }
            message+= " have been added to the conversation.";
        }
        window.addSystemMessage(message);
        } 
    }
    
    /**
     * get the Map of convIDs to MacheGUIs associated to this
     * MacheController. Method only used in tests.
     * 
     * @return windows
     */
    public Map<String, MacheGUI> getWindows() {
        return windows;
    }

    
    /**
     * get the username associated to this MacheController.
     * Method only used in tests.
     * @return username
     */
    protected String getUsername() {
        return username;
    }

}
